﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Web;
using System.Text;
using NUnit.Framework;
using Obra.SmugMug.Api;
using System.ServiceModel.Description;
using System.IO;
using Obra.Api;
using Obra.Test.SmugMug;
using NMock2;

namespace Obra.Test
{
    /// <summary>
    /// These are integration level tests that mimic a request to smmugmug.com,
    /// and the processing of the response through WCF.
    /// </summary>
    [TestFixture]
    public class SmugMugHttpResponse
    {
        private Uri uri = new Uri(Messages.TestUrl);
        private WebChannelFactory<ISmugMug> factory;
        private ISmugMug client;
        private Mockery mockery;
        
        public ISmugMug Client
        {
            get { return client; }
        }

        [SetUp]
        public void SetUp()
        {
            this.mockery = new Mockery();
            this.factory = new WebChannelFactory<ISmugMug>(
                new WebHttpBinding(),
                new Uri(Messages.TestUrl));

            this.factory.Endpoint.Behaviors.Add(
                new EndpointBehavior());

            this.factory.Endpoint.Behaviors.Add(
                new WebHttpBehavior());

            this.client = this.factory.CreateChannel();
        }

        [TearDown]
        public void TearDown()
        {
            this.factory.Close();
            this.mockery.VerifyAllExpectationsHaveBeenMet();
        }
      
        [Test]
        public void SmugMugResponse_Error()
        {
            string content = File.ReadAllText(@"..\..\SmugMug\sample\SmugMugInvalidApiKey.xml");

            using (HttpServerQueuedContent httpServer = new HttpServerQueuedContent(this.uri))
            {
                httpServer.ContentQueue.Enqueue(content);
                httpServer.Start();

                try
                {
                    LoginWithPasswordContract loginWithPassword = this.Client.LoginWithPassword(
                        "abc@def.com",
                        "secret",
                        "API");
                }
                catch (SmugMugException e)
                {
                    Assert.AreEqual("invalid API key", e.Message);
                }
                catch (Exception)
                {
                    Assert.Fail("Should not have reached this exception");
                }
            }
        }

        [Test]
        public void SmugMugResponse_LoginWithPassword()
        {
            string content = File.ReadAllText(@"..\..\SmugMug\sample\SmugMugLoginWithPassword.xml");

            using (HttpServerQueuedContent httpServer = new HttpServerQueuedContent(this.uri))
            {
                httpServer.ContentQueue.Enqueue(content);
                httpServer.RequestValidateQueue.Enqueue(new SmugMugUserAgentValidate());
                httpServer.Start();

                LoginWithPasswordContract loginWithPassword = this.Client.LoginWithPassword(
                    "abc@def.com",
                    "secret",
                    "API");

                // Deserialization is already tested, so just check a few values.
                Assert.AreEqual(AccountType.Pro, loginWithPassword.AccountType);
                Assert.AreEqual(1234, loginWithPassword.User.Id);
                Assert.AreEqual("c525168360b919d19135993990a992bd", loginWithPassword.Session.Id);
            }
        }

        [Test]
        public void SmugMugResponse_ChangeAlbumSettings()
        {
            var factory = new WebChannelFactory<ISmugMugClient>(
                new WebHttpBinding(),
                new Uri(Messages.TestUrl));

            factory.Endpoint.Behaviors.Add(
                new EndpointBehavior());

            factory.Endpoint.Behaviors.Add(
                new WebHttpBehavior());

            var client = factory.CreateChannel();

            string content_login = File.ReadAllText(@"..\..\SmugMug\sample\SmugMugLoginWithPassword.xml");
            string content_albums = File.ReadAllText(@"..\..\SmugMug\sample\SmugMugAlbumsGet.xml");
            string content_albumSettingsSet = File.ReadAllText(@"..\..\SmugMug\sample\SmugMugAlbumsChangeSettings.xml");
            string content_albumSettingsClear = File.ReadAllText(@"..\..\SmugMug\sample\SmugMugAlbumsChangeSettings.xml");

            using (HttpServerQueuedContent httpServer = new HttpServerQueuedContent(this.uri))
            {
                httpServer.ContentQueue.Enqueue(content_login);
                httpServer.ContentQueue.Enqueue(content_albums);
                httpServer.ContentQueue.Enqueue(content_albumSettingsSet);
                httpServer.ContentQueue.Enqueue(content_albumSettingsClear);
                httpServer.RequestValidateQueue.Enqueue(new SmugMugUserAgentValidate());
                httpServer.RequestValidateQueue.Enqueue(new SmugMugUriQueryBooleanValidate());
                httpServer.Start();

                LoginWithPasswordContract loginWithPassword = client.LoginWithPassword(
                    "abc@def.com",
                    "secret",
                    "API");

                var albums = client.GetAlbums(loginWithPassword.SessionId);
                client.ChangeAlbumCanRank(loginWithPassword.SessionId, albums.Albums[0].Id, true);
                client.ChangeAlbumCanRank(loginWithPassword.SessionId, albums.Albums[0].Id, false);
            }
        }

        [Test]
        public void UploadOneFile()
        {
            string data = "this-is-image-data";
            string loginWithPasswordContent = File.ReadAllText(@"..\..\SmugMug\sample\SmugMugLoginWithPassword.xml");
            string uploadContent = File.ReadAllText(@"..\..\Smugmug\sample\SmugMugUpload.xml");
            string logoutContent = File.ReadAllText(@"..\..\SmugMug\sample\SmugMugLogout.xml");

            using (HttpServerQueuedContent httpServer = new HttpServerQueuedContent(this.uri))
            using (MediaServiceProvider service = new MediaServiceProvider(
                new WebHttpBinding(),
                new EndpointAddress(Messages.TestUrl)))
            {
                httpServer.Start();

                IUploadService uploadService = new UploadServiceProvider(
                    "c525168360b919d19135993990a992bd",
                    Messages.TestUrl);

                service.AddService(typeof(IUploadService), uploadService);

                httpServer.ContentQueue.Enqueue(loginWithPasswordContent);
                httpServer.ContentQueue.Enqueue(uploadContent);
                httpServer.ContentQueue.Enqueue(logoutContent);
                httpServer.RequestValidateQueue.Enqueue(new SmugMugUserAgentValidate());

                SmugMugUploadRequestValidate validator = new SmugMugUploadRequestValidate()
                {
                    ExpectedAlbumId = "1000",
                    ExpectedChecksum = TestHelper.ComputeMD5ChecksumOfString(data),
                    ExpectedFileName = "image-that-does-not-already-exist.jpg",
                    ExpectedImageId = null,
                    ExpectedLength = (ulong)data.Length,
                    ExpectedResponseType = "REST",
                    ExpectedSessionId = "c525168360b919d19135993990a992bd",
                    ExpectedVersion = "1.2.0",
                };

                service.LogOn("abc@def.com", "secret");
                Assert.AreEqual("c525168360b919d19135993990a992bd", service.Session.SessionId);

                IAlbum album = this.mockery.NewMock<IAlbum>();
                Expect.Once.On(album).GetProperty("Id").Will(Return.Value("1000"));
                Expect.Once.On(album).GetProperty("Name").Will(Return.Value("Album1"));
                Expect.Once.On(album).Method("Contains").Will(Return.Value(false));

                httpServer.RequestValidateQueue.Enqueue(validator);
                service.UploadMediaFile(
                    album,
                    "image-that-does-not-already-exist.jpg",
                    TestHelper.GetStreamFromString("this-is-image-data"));

                // Remove the upload validator because it will not validate logout.
                httpServer.RequestValidateQueue.Clear();
                httpServer.RequestValidateQueue.Enqueue(new SmugMugUserAgentValidate());
            }
        }

        [Test]
        public void UploadOneFileOverwriteExistingImage()
        {
            string data = "this-is-image-data";
            string loginWithPasswordContent = File.ReadAllText(@"..\..\SmugMug\sample\SmugMugLoginWithPassword.xml");
            string uploadContent = File.ReadAllText(@"..\..\SmugMug\sample\SmugMugUpload.xml");
            string logoutContent = File.ReadAllText(@"..\..\SmugMug\sample\SmugMugLogout.xml");

            using (HttpServerQueuedContent httpServer = new HttpServerQueuedContent(this.uri))
            using (MediaServiceProvider service = new MediaServiceProvider(
                new WebHttpBinding(),
                new EndpointAddress(Messages.TestUrl)))
            {
                httpServer.Start();

                IUploadService uploadService = new UploadServiceProvider(
                    "c525168360b919d19135993990a992bd",
                    Messages.TestUrl);

                service.AddService(typeof(IUploadService), uploadService);

                httpServer.ContentQueue.Enqueue(loginWithPasswordContent);
                httpServer.ContentQueue.Enqueue(uploadContent);
                httpServer.ContentQueue.Enqueue(logoutContent);
                httpServer.RequestValidateQueue.Enqueue(new SmugMugUserAgentValidate());

                SmugMugUploadRequestValidate validator = new SmugMugUploadRequestValidate()
                {
                    ExpectedAlbumId = "1000",
                    ExpectedChecksum = TestHelper.ComputeMD5ChecksumOfString(data),
                    ExpectedFileName = "image-1.jpg",
                    ExpectedImageId = "1001",
                    ExpectedLength = (ulong)data.Length,
                    ExpectedResponseType = "REST",
                    ExpectedSessionId = "c525168360b919d19135993990a992bd",
                    ExpectedVersion = "1.2.0",
                };

                service.LogOn("abc@def.com", "secret");
                Assert.AreEqual("c525168360b919d19135993990a992bd", service.Session.SessionId);

                IMedia media = this.mockery.NewMock<IMedia>();
                Expect.Once.On(media).GetProperty("Id").Will(Return.Value("1001"));

                IAlbum album = this.mockery.NewMock<IAlbum>();
                Expect.Once.On(album).GetProperty("Id").Will(Return.Value("1000"));
                Expect.Once.On(album).GetProperty("Name").Will(Return.Value("Album1"));
                Expect.Once.On(album).Method("Contains").With("image-1.jpg").Will(Return.Value(true));
                //Expect.Once.On(album).GetProperty("Item").Will(Return.Value(media));
                Expect.Once.On(album).Get["image-1.jpg"].Will(Return.Value(media));

                httpServer.RequestValidateQueue.Enqueue(validator);
                service.UploadMediaFile(
                    album,
                    "image-1.jpg",
                    TestHelper.GetStreamFromString("this-is-image-data"));

                // Remove the upload validator because it will not validate logout.
                httpServer.RequestValidateQueue.Clear();
                httpServer.RequestValidateQueue.Enqueue(new SmugMugUserAgentValidate());
            }
        }
    }
}
